package com.gsit.expenditure.controller;

import java.awt.Desktop;
import java.io.File;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import static com.gsit.expenditure.utils.BilConverter.converterBean;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.util.Callback;
import javafx.util.StringConverter;

import javax.validation.Validation;
import javax.validation.Validator;

import com.gsit.expenditure.client.domina.BillBean;
import com.gsit.expenditure.client.domina.FXMLBase;
import com.gsit.expenditure.client.domina.InvoiceBean;
import com.gsit.expenditure.client.domina.OtherBillBean;
import com.gsit.expenditure.client.domina.TravelbillBean;
import com.gsit.expenditure.component.CheckBoxTableCell;
import com.gsit.expenditure.domain.Bill;
import com.gsit.expenditure.domain.Customer;
import com.gsit.expenditure.domain.Invoice;
import com.gsit.expenditure.domain.InvoiceStorage;
import com.gsit.expenditure.domain.OtherBill;
import com.gsit.expenditure.domain.TravelBill;
import com.gsit.expenditure.report.MainApp;
import com.gsit.expenditure.services.BillService;
import com.gsit.expenditure.services.InvoiceService;
import com.gsit.expenditure.utils.AppContextLoader;
import com.gsit.expenditure.utils.BillStatus;
import com.gsit.expenditure.utils.InvoiceNumberGenerator;
import com.gsit.expenditure.utils.InvoiceStatus;
import com.gsit.expenditure.utils.Page;
import com.gsit.expenditure.utils.Utils;
import com.gsit.expenditure.utils.ViewHandler;

import eu.schudt.javafx.controls.calendar.DatePicker;




public class InvoiceController extends BaseController implements Initializable {

	//@FXML private TextField customerName;
	
	
	@FXML private ComboBox<Customer> customerName;
	@FXML private ComboBox<BillStatus> billState ;
	
	@FXML private HBox dateHbox;
	@FXML private DatePicker fromDate;
	
	@FXML private HBox dateHbox1;
	@FXML private DatePicker toDate;
	
	//@FXML private TextField distanceText;
	@FXML private Button searchVehicleButton;
	@FXML private Button addInvoiceButton;
	
	// for populating data in table
	@FXML private TableView<BillBean> invoiceTable ;
	
	@FXML private TableColumn<BillBean, String> serialNumberColumn;
	@FXML private TableColumn<BillBean, String> dateColumn;
	@FXML private TableColumn<BillBean, String> referenceNoColumn;
	@FXML private TableColumn<BillBean, String> particularsColumn;
	@FXML private TableColumn<BillBean, String> otherBillColumn;
	@FXML private TableColumn<BillBean, String> amountColumn; 
	
	@FXML private TableColumn<BillBean, Boolean> selectColumn ;
	
	private InvoiceBean invoiceBean;
	private InvoiceService invoiceService;
	private BillService billService;
	private List<Bill> billList;
	private Validator validator;
		
	Date selectedFromDate;
	Date selectedToDate;
	
	//ERROR LABELS
	@FXML private Label invoiceErrorLabel;
	@FXML private Label custNameErrorLabel;
	
	private ObservableList<BillBean> observableList = FXCollections.observableArrayList() ;
	
	private final InvoiceController invoiceController = this;
	
	@Override
	public void initialize(URL url, ResourceBundle bundle) {
		
		invoiceService = AppContextLoader.getBean(InvoiceService.class);
		billService = AppContextLoader.getBean(BillService.class);
		invoiceBean = new InvoiceBean(null);
		dateHbox.getChildren();

		fromDate = new DatePicker(Locale.ENGLISH);
		fromDate.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
		fromDate.getCalendarView().todayButtonTextProperty().set("Today");
		fromDate.getCalendarView().setShowWeeks(false);
		fromDate.getStylesheets().add("css/datepicker/DatePicker.css");
		// Add DatePicker to grid
		dateHbox.getChildren().add(fromDate);
			
		toDate = new DatePicker(Locale.ENGLISH);
		toDate.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
		toDate.getCalendarView().todayButtonTextProperty().set("Today");
		toDate.getCalendarView().setShowWeeks(false);
		toDate.getStylesheets().add("css/datepicker/DatePicker.css");
		dateHbox1.getChildren().add(toDate);
		
		customerName.getItems().addAll(billService.findCustomerName());
		billState.getItems().addAll(BillStatus.values());
		
		// CONVERTER FOR customername FIELD
		customerName.setConverter(new StringConverter<Customer>() {
			@Override
			public String toString(Customer customer) {
				return customer.getFirstName();
			}

			@Override
			public Customer fromString(String customerName) {
				List<Customer> customers = billService.findCustomerName();
				Customer customer = null;
				for (Customer customer2 : customers) {
					if (customer2.getFirstName().equals(customerName)) {
						System.out.println("Customer FirstName>>>>>>>>>>>>>>"+ customerName);
						customer = customer2;
						break;
					}
				}
				return customer;
			}
		});
		
		invoiceTable.setOnMouseClicked(new UpdateBillEvent());
		initTable();
		bind();
	}

	
	private void initTable() {
		
		serialNumberColumn.setCellValueFactory(new PropertyValueFactory<BillBean, String>("serialNumber"));
		dateColumn.setCellValueFactory(new PropertyValueFactory<BillBean, String>("billDate"));
		referenceNoColumn.setCellValueFactory(new PropertyValueFactory<BillBean, String>("referenceNumber"));
		amountColumn.setCellValueFactory(new PropertyValueFactory<BillBean, String>("amount"));
		particularsColumn.setCellValueFactory(new PropertyValueFactory<BillBean, String>("particulars"));
		otherBillColumn.setCellValueFactory(new PropertyValueFactory<BillBean, String>("description"));
		
		//CHECKBOX
		selectColumn.setCellFactory(new Callback<TableColumn<BillBean, Boolean>, TableCell<BillBean, Boolean>>() {

            public TableCell<BillBean, Boolean> call(TableColumn<BillBean, Boolean> p) {
              	return new CheckBoxTableCell<BillBean, Boolean>();
            }
        });
	   selectColumn.setCellValueFactory(new PropertyValueFactory<BillBean, Boolean>("select"));
	}

	private void bind() {
		
	}

	@Override
	public void onSave() {
		invoiceService.saveOrUpdate(invoiceBean.getObject());
	}
	
	
	public void onSearch() {
		Customer customer = customerName.getSelectionModel().getSelectedItem();
		Invoice invoiceBea = invoiceBean.getObject();
		
		if (isValidate(invoiceBea, customer)) {
			Date selectedFromDate = fromDate.getSelectedDate();
			Date selectedToDate = toDate.getSelectedDate();
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			
			BillStatus billStatus = billState.getSelectionModel().getSelectedItem();

			String fromDateString = "";
			String toDateString = "";
			if (selectedFromDate != null) {
				fromDateString = dateFormat.format(selectedFromDate);
			}
			if (selectedToDate != null) {
				toDateString = dateFormat.format(selectedToDate);
			}
			if (billStatus == null) {
				billStatus = billStatus.NEW;
			}
			
			billList = billService.findBillByConsumerAndBillDate(customer.getId(), billStatus, fromDateString, toDateString);
		}
		onLoad(); 
	}
	
	//Generate PDF Files
	public void addInvoice() {
		int invoiceNumber = InvoiceNumberGenerator.getInstance().getCounter();
		final String FILE_EXT = ".pdf";

		StringBuffer path = Utils.getDestinationPath();
		path.append("/");
		path.append(invoiceNumber + FILE_EXT);

		Set<BillBean> billBeans = (Set<BillBean>) CheckBoxTableCell.getSelectedItemSet();
		if (billBeans != null && billBeans.size() > 0) {

			Invoice invoice = new Invoice();
			invoice.setInvoiceNumber("" + invoiceNumber);
			invoice.setCreatedDate(Utils.getCurrentDate());
			invoice.setModifiedDate(Utils.getCurrentDate());
			// invoice.setVersion(1L);
			invoice.setStatus(InvoiceStatus.UNPAID);

			Set<Bill> bills = new HashSet<>();
			for (BillBean billBean : billBeans) {
				Bill bill = billBean.getBill();
				bill.setStatus(BillStatus.INVOICED);
				bill.setModifiedDate(Utils.getCurrentDate());
				// billService.saveOrUpdateBill(bill);
				bill.setInvoice(invoice);
				System.out.println("Bill :: " + bill.toString());
				bills.add(bill);
			}

			invoice.setBills(bills);

			// create jasper report
			try {

				MainApp app = new MainApp();
				app.createJasperReportForInvoice(Utils.SOURCE_PATH, path.toString(), converterBean(billBeans));

				InvoiceStorage invoiceStorage = new InvoiceStorage();
				invoiceStorage.setFileLocation(path.toString());
				invoiceStorage.setCreatedDate(Utils.getCurrentDate());
				invoiceStorage.setModifiedDate(Utils.getCurrentDate());
				invoice.setInvoiceStorage(invoiceStorage);
				invoice = invoiceService.saveOrUpdate(invoice);

				showInvoicePopup();
				stateChange.set(!stateChange.getValue());

			} catch (Exception e) {
				e.printStackTrace();
			}

			CheckBoxTableCell.setSelectedItemSet(null);
			onSearch();

		} else {
			showFailurePopup();
			stateChange.set(!stateChange.getValue());
		}

		onSearch();
		
}

	//3-2-13
	//show preview in pdf file	
	public void onPreviewLink(){
		
		Set<BillBean> billBeans = (Set<BillBean>) CheckBoxTableCell.getSelectedItemSet();
		System.out.println("Set BIllBeans 1***************"+billBeans.size());
		
		if (billBeans.size() > 0 ) {
			try {
				  
				MainApp app=new MainApp();
				app.createJasperReportForInvoice(Utils.SOURCE_PATH, Utils.getPreviewPath().toString(), converterBean(billBeans));
				Desktop.getDesktop().open(new File(Utils.getPreviewPath().toString()));
				CheckBoxTableCell.setSelectedItemSet(null);
				System.out.println("*****************Create Preview File******************");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		else{
			showFailurePopup();
			stateChange.set(!stateChange.getValue());
		}
		
		}
private void showFailurePopup(){
		final FXMLBase<FailureInvoiceController> fxmlBase =  ViewHandler.createFXMLBase(Page.INVOICE_FAILURE_MSG);
		fxmlBase.getController().getStateChange().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> arg0,Boolean oldVal, Boolean newVal) {
				if(newVal){
					fxmlBase.getDialogStage().hide();
					//MainAppController.loadNext(Page.CREATE_INVOICES);
				}
			}
		});
	
		ViewHandler.createDialog(fxmlBase, "Failure .");
		fxmlBase.getDialogStage().showAndWait();
	}
	
	
	private void showInvoicePopup(){
		final FXMLBase<SuccessController> fxmlBase =  ViewHandler.createFXMLBase(Page.SUCCESS_MSG);
		fxmlBase.getController().getStateChange().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> arg0,Boolean oldVal, Boolean newVal) {
				if(newVal){
					fxmlBase.getDialogStage().hide();
					//MainAppController.loadNext(Page.SEARCH_CUSTOMER);
				}
			}
		});
		ViewHandler.createDialog(fxmlBase, "Invoice has been successfully created .");
		fxmlBase.getDialogStage().showAndWait();
	}
	
	@Override
	public void onLoad() {
		
		if(billList != null ){ 
			invoiceTable.getItems().clear();
			observableList.clear();
			List<BillBean> beans  = new ArrayList<>();
			for (Bill bill : billList) {
				BillBean billBean = new BillBean(bill);
				beans.add(billBean);
			}
			observableList.addAll(beans) ;
			invoiceTable.setItems(observableList);
		}
		
	}
	
	public Boolean isValidate(Invoice invoice, Customer customer){
		
		clearAllErrorLabels();
		Boolean result = Boolean.TRUE;
		if(validator == null){
			validator=Validation.buildDefaultValidatorFactory().getValidator();
		}
		invoice.setCreatedDate(fromDate.getSelectedDate());
		invoice.setModifiedDate(toDate.getSelectedDate());
		
		if (fromDate.getSelectedDate()!=null ) {
				if (fromDate.getSelectedDate().after(new java.util.Date()) ){
					invoiceErrorLabel.setText("FromDate Should not be future date");
		}
		}
		if (toDate.getSelectedDate()!=null ) {
			if (toDate.getSelectedDate().after(new java.util.Date()) ){
				invoiceErrorLabel.setText("ToDate Should not be future date");
		}
		}
		if (customer == null) {
			invoiceErrorLabel.setText("Select customer name");
		}
		return result;
	}
	
	
	

	private void clearAllErrorLabels() {
		invoiceErrorLabel.setText("");
	}
	

	private class UpdateBillEvent implements EventHandler<MouseEvent>{
		
		 FXMLBase<TravelbillController> travelBillFxmlBase = null ;
		 FXMLBase<OtherbillController> otherBillFxmlBase = null ;
		
		@Override
		public void handle(MouseEvent mEvent) {
			if (mEvent.getButton().equals(MouseButton.PRIMARY)) {
				if (mEvent.getClickCount() == 2) {
					
					BillBean billBean = (BillBean) invoiceTable.getSelectionModel().getSelectedItem();

					if (billBean != null) {
						if (billBean.getBill() instanceof TravelBill) {
							travelBillFxmlBase = ViewHandler.createFXMLBase(Page.TRAVEL_BILL);
							
							TravelbillBean bean = new TravelbillBean(null) ;
							bean.reLoad((TravelBill)billBean.getBill());
							travelBillFxmlBase.getController().reLoad(bean);
							
							ViewHandler.createDialog(travelBillFxmlBase, " Update Travel bill......");
							travelBillFxmlBase.getController().getStateChange().addListener(new ChangeListener<Boolean>() {
									@Override
									public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldValue, Boolean newValue) {
											if (newValue) {
												travelBillFxmlBase.getDialogStage().hide();
												invoiceController.onSearch();
											}
										}
									});
							travelBillFxmlBase.getDialogStage().showAndWait();
						}else {
							otherBillFxmlBase = ViewHandler.createFXMLBase(Page.OTHER_BILL);
							OtherBillBean otherBillBean = new OtherBillBean(null);
							otherBillBean.reLoad((OtherBill)billBean.getBill());
							
							otherBillFxmlBase.getController().reLoad(otherBillBean);
							ViewHandler.createDialog(otherBillFxmlBase,"Update Other bill......");
							otherBillFxmlBase.getController().getStateChange().addListener(new ChangeListener<Boolean>() {
									public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldValue, Boolean newValue) {
											if (newValue) {
												otherBillFxmlBase.getDialogStage().hide();
												invoiceController.onSearch();
											}
										}
									});
					
									otherBillFxmlBase.getDialogStage().showAndWait();

						}
					}

				}
			}
		}
	}
			
		
		}
	






